package service

import (
	"encoding/json"
	"errors"
	baseStore "gitee.com/zaiqiang231/go-base-app/base_app/store"
	"gitee.com/zaiqiang231/zcamp-service-camp/app/model"
	"gitee.com/zaiqiang231/zcamp-service-camp/app/model/req"
	"gorm.io/gorm"
	"sort"
)

type ServiceCondition struct{}

var ServiceConditionInstance = new(ServiceCondition)

func (service *ServiceCondition) Create(item *req.ConditionCreateReq) (err error) {
	baseStore.GetDataStore().Execute(func(db *gorm.DB) {
		err = db.Create(&item).Error
	})
	return
}

func (service *ServiceCondition) GetById(id int64) (target model.Condition, err error) {
	baseStore.GetDataStore().Execute(func(db *gorm.DB) {
		err = db.Where("id = ?", id).Find(&target).Error
	})
	return
}

func (service *ServiceCondition) GetList(info req.ConditionListReq) (list interface{}, total int64, err error) {
	baseStore.GetDataStore().Execute(func(db *gorm.DB) {
		limit := info.PageSize
		offset := info.PageSize * (info.Page - 1)
		var tempDb = db
		if info.ID != 0 {
			tempDb = tempDb.Where("id = ?", info.ID)
		}
		if info.Name != "" {
			tempDb = tempDb.Where("name LIKE ?", "%"+info.Name+"%")
		}
		if info.ParentId >= 0 {
			tempDb = tempDb.Where("parent_id = ?", info.ParentId)
		}
		if info.Status != 0 {
			tempDb = tempDb.Where("status = ?", info.Status)
		}
		var tmpList []model.Condition
		err = tempDb.Model(&model.Condition{}).Count(&total).Error
		if err != nil {
			return
		}
		err = tempDb.Model(&model.Condition{}).Offset(offset).Limit(limit).Find(&tmpList).Error
		if err != nil {
			return
		}
		list = tmpList
	})
	return
}

func (service *ServiceCondition) GetTree(request req.ConditionTreeReq) (treeHead *model.ConditionTree, err error) {
	baseStore.GetDataStore().Execute(func(db *gorm.DB) {
		treeHead, err = getTreeByRecursion(request.TreeId, db)
		if err != nil {
			return
		}
	})
	return
}

func getTreeByRecursion(id uint, db *gorm.DB) (*model.ConditionTree, error) {
	var result = new(model.ConditionTree)
	var err error
	if id > 0 {
		err = db.Model(model.Condition{}).Where("id = ?", id).Find(&result).Error
		if err != nil {
			return nil, err
		}
	}
	err = db.Model(model.Condition{}).Where("parent_id = ?", id).Order("sort desc").Find(&result.Children).Error
	for _, child := range result.Children {
		//log.Printf("child name %s %p ", child.Name, &child)
		tempHead, temperr := getTreeByRecursion(child.ID, db)
		if temperr != nil {
			err = temperr
			return nil, err
		}
		child.Children = tempHead.Children
	}
	return result, err
}

// 性能对比
func (service *ServiceCondition) GetTree2(request req.ConditionTreeReq) (treeHead *model.ConditionTree, err error) {
	baseStore.GetDataStore().Execute(func(db *gorm.DB) {
		var datas = make([]model.Condition, 0)

		err = db.Model(model.Condition{}).Find(&datas).Error
		if err != nil {
			return
		}
		var headCondition model.Condition
		conditionMap := make(map[int64][]model.Condition)

		for _, v := range datas {
			if request.TreeId == v.ID {
				headCondition = v
			}
			if _, ok := conditionMap[v.ParentId]; !ok {
				conditionMap[v.ParentId] = make([]model.Condition, 0)
			}
			conditionMap[v.ParentId] = append(conditionMap[v.ParentId], v)
		}

		treeHead, err = getConditionTreeByRecursion2(headCondition, conditionMap)
		if err != nil {
			return
		}
	})
	return
}

func getConditionTreeByRecursion2(head model.Condition, datas map[int64][]model.Condition) (*model.ConditionTree, error) {
	var result = new(model.ConditionTree)
	result.Condition = head
	result.Children = make([]*model.ConditionTree, 0)
	var err error
	for _, child := range datas[int64(head.ID)] {
		tempHead, temperr := getConditionTreeByRecursion2(child, datas)
		if temperr != nil {
			err = temperr
			return nil, err
		}
		result.Children = append(result.Children, tempHead)
	}
	sort.SliceStable(result.Children, func(i, j int) bool {
		return result.Children[i].Sort > result.Children[j].Sort
	})
	return result, err
}

func (service *ServiceCondition) DeleteList(info req.IdsReq) (err error) {
	baseStore.GetDataStore().Execute(func(db *gorm.DB) {
		var tmpList []model.Condition
		err = db.Model(&model.Condition{}).Where("id in ?", info.Ids).Find(&tmpList).Delete(&tmpList).Error
	})
	return
}

func (service *ServiceCondition) UpdateForMap(info map[string]interface{}) (err error) {
	baseStore.GetDataStore().Execute(func(db *gorm.DB) {
		var old model.Condition
		if errors.Is(db.Where("id = ?", info["id"]).First(&old).Error, gorm.ErrRecordNotFound) {
			err = errors.New("原记录不存在")
		}
		if err != nil {
			return
		}
		delete(info, "updated_at")
		err = db.Model(&old).Omit("id", "created_at", "deleted_at").Updates(info).Error
	})
	return err
}

func (service *ServiceCondition) HotCondition() (list interface{}, err error) {
	baseStore.GetDataStore().Execute(func(db *gorm.DB) {
		var datas = make([]model.Condition, 0)
		err = db.Model(model.Condition{}).Find(&datas).Error
		if err != nil {
			return
		}

		conditionList := make([]model.Condition, 0)
		conditionMap := make(map[int64]model.Condition)
		for _, v := range datas {
			conditionMap[int64(v.ID)] = v
			if v.Level == 3 {
				conditionList = append(conditionList, v)
			}
		}

		hotList := make([]model.HotCondition, 0)
		for _, v := range conditionList {
			hotList = append(hotList, model.HotCondition{
				Condition:         v,
				ParentMultiSelect: conditionMap[v.ParentId].MultiSelect,
			})
		}

		list = hotList
	})
	return
}

func (service *ServiceCondition) CampDetailCondition(availableList []int64) (list []model.CampDetailCondition, err error) {
	baseStore.GetDataStore().Execute(func(db *gorm.DB) {
		var datas = make([]model.Condition, 0)
		err = db.Model(model.Condition{}).Find(&datas).Error
		if err != nil {
			return
		}

		availableMap := make(map[int64]int64)
		for _, v := range availableList {
			availableMap[v] = v
		}

		conditionList := make([]model.Condition, 0)
		conditionMap := make(map[int64]model.Condition)
		for _, v := range datas {
			conditionMap[int64(v.ID)] = v
			if v.Level == 3 {
				conditionList = append(conditionList, v)
			}
		}

		detailList := make([]model.CampDetailCondition, 0)
		for _, v := range conditionList {
			tempData := model.CampDetailCondition{
				Condition:  v,
				ParentName: conditionMap[v.ParentId].Name,
			}

			if _, ok := availableMap[int64(v.ID)]; ok {
				tempData.Value = 1
			}

			var conditionImages []req.ConditionImages
			tmperr := json.Unmarshal([]byte(v.Pictures), &conditionImages)
			if tmperr == nil {
				for i := 0; i < len(conditionImages); i++ {
					temp := conditionImages[i]
					if tempData.Value == 1 {
						if temp.Status == model.ConditionPictureAvailable {
							tempData.Icon = temp.Url
						}
					} else {
						if temp.Status != model.ConditionPictureAvailable {
							tempData.Icon = temp.Url
						}
					}
				}
			}
			detailList = append(detailList, tempData)
		}

		list = detailList
	})
	return
}
